package org.javahispano.javacup.tacticas_aceptadas.brunopon;

import java.awt.Color;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import org.javahispano.javacup.modelo.Comando;
import org.javahispano.javacup.modelo.ComandoGolpearBalon;
import org.javahispano.javacup.modelo.ComandoIrA;
import org.javahispano.javacup.modelo.Constantes;
import org.javahispano.javacup.modelo.EstiloUniforme;
import org.javahispano.javacup.modelo.JugadorDetalle;
import org.javahispano.javacup.modelo.Posicion;
import org.javahispano.javacup.modelo.SituacionPartido;
import org.javahispano.javacup.modelo.Tactica;
import org.javahispano.javacup.modelo.TacticaDetalle;

public class TacticaXbp implements Tactica {
	private static int J1 = 0;
	private static int JA = 1;
	private static int J3 = 2;
	private static int J4 = 3;
	private static int J5 = 4;
	private static int J6 = 5;
	private static int J9 = 8;
	private static int J10 = 9;
	private static int J11 = 10;
	private static double LAT = Constantes.ANCHO_CAMPO_JUEGO / 2;
	private static double FON = Constantes.LARGO_CAMPO_JUEGO / 2;
	private static Posicion ARCO = Constantes.centroArcoSup;
	private static Posicion ARCO_MIO = Constantes.centroArcoInf;
	
	TacticaBmpDetalle detalle = new TacticaBmpDetalle();

    Posicion alineacion1[]=new Posicion[]{
        new Posicion(-0.951048951048951,-48),
        new Posicion(-0.23776223776223776,-51.31221719457013),
        new Posicion(-19.97202797202797,-35.63348416289593),
        new Posicion(17.832167832167833,-36.34615384615385),
        new Posicion(7.846153846153847,-15.441176470588236),
        new Posicion(-9.986013986013985,-14.728506787330318),
        new Posicion(-25.678321678321677,1.6628959276018098),
        new Posicion(23.776223776223777,1.900452488687783),
        new Posicion(-19.97202797202797,25.418552036199095),
        new Posicion(-0.951048951048951,9.264705882352942),
        new Posicion(19.25874125874126,25.418552036199095)
    };

    Posicion alineacion2[]=new Posicion[]{
        new Posicion(0.0,-41.57239819004525),
        new Posicion(0.23776223776223776,-51.074660633484164),
        new Posicion(-19.020979020979023,-35.39592760180996),
        new Posicion(19.25874125874126,-35.8710407239819),
        new Posicion(10.223776223776223,-13.065610859728507),
        new Posicion(-12.125874125874127,-12.59049773755656),
        new Posicion(-25.202797202797203,3.800904977375566),
        new Posicion(25.44055944055944,3.800904977375566),
        new Posicion(-19.734265734265733,32.54524886877828),
        new Posicion(-0.23776223776223776,10.927601809954751),
        new Posicion(18.78321678321678,32.07013574660634)
    };

    Posicion alineacion3[]=new Posicion[]{
        new Posicion(0.0,-33.970588235294116),
        new Posicion(-0.23776223776223776,-51.549773755656105),
        new Posicion(-22.11188811188811,-22.805429864253394),
        new Posicion(20.923076923076923,-24.230769230769234),
        new Posicion(10.461538461538462,-4.276018099547511),
        new Posicion(-10.6993006993007,-4.276018099547511),
        new Posicion(-27.81818181818182,17.34162895927602),
        new Posicion(26.153846153846157,18.529411764705884),
        new Posicion(-16.405594405594407,36.10859728506787),
        new Posicion(-1.4265734265734267,16.866515837104075),
        new Posicion(15.692307692307693,36.34615384615385)
    };

    Posicion alineacion4[]=new Posicion[]{
        new Posicion(6.419580419580419,-42.522624434389144),
        new Posicion(0.0,-51.549773755656105),
        new Posicion(-9.748251748251748,-37.29638009049774),
        new Posicion(16.405594405594407,-30.407239819004527),
        new Posicion(-14.265734265734267,-23.518099547511312),
        new Posicion(16.88111888111888,-12.828054298642533),
        new Posicion(-16.167832167832167,-0.7126696832579186),
        new Posicion(16.643356643356643,10.452488687782806),
        new Posicion(-9.748251748251748,36.10859728506787),
        new Posicion(-14.503496503496503,19.2420814479638),
        new Posicion(17.832167832167833,31.357466063348415)
    };

    Posicion alineacion5[]=new Posicion[]{
        new Posicion(-0.4755244755244755,-35.15837104072398),
        new Posicion(0.0,-51.31221719457013),
        new Posicion(-16.643356643356643,-34.44570135746606),
        new Posicion(16.643356643356643,-33.970588235294116),
        new Posicion(17.11888111888112,-18.054298642533936),
        new Posicion(-16.88111888111888,-18.766968325791854),
        new Posicion(-21.636363636363637,-0.7126696832579186),
        new Posicion(17.594405594405593,0.0),
        new Posicion(-18.06993006993007,-0.47511312217194573),
        new Posicion(0.2595419847328244,-0.26119402985074625),
        new Posicion(15.216783216783217,-0.23755656108597287)
    };

    Posicion alineacion6[]=new Posicion[]{
        new Posicion(0.4755244755244755,-37.05882352941177),
        new Posicion(0.951048951048951,-51.787330316742086),
        new Posicion(-15.93006993006993,-32.54524886877828),
        new Posicion(13.314685314685315,-33.02036199095023),
        new Posicion(13.552447552447552,-19.95475113122172),
        new Posicion(-17.356643356643357,-19.2420814479638),
        new Posicion(-24.013986013986013,-4.98868778280543),
        new Posicion(19.496503496503497,-5.463800904977376),
        new Posicion(-10.223776223776223,-4.751131221719457),
        new Posicion(-0.23776223776223776,-9.97737556561086),
        new Posicion(11.65034965034965,-4.98868778280543)
    };
        
    class TacticaBmpDetalle implements TacticaDetalle {

        public String getNombre() {
            return "XBP";
        }

        public String getPais() {
            return "Argentina";
        }

        public String getEntrenador() {
            return "Bruno";
        }

        public Color getColorCamiseta() {
            return new Color(0, 0, 0);
        }

        public Color getColorPantalon() {
            return new Color(0, 0, 0);
        }

        public Color getColorFranja() {
            return new Color(0, 0, 0);
        }

        public Color getColorCalcetas() {
            return new Color(0, 0, 0);
        }

        public Color getColorPortero() {
            return new Color(255, 255, 0        );
        }

        public EstiloUniforme getEstilo() {
            return EstiloUniforme.SIN_ESTILO;
        }

        public Color getColorCamiseta2() {
            return new Color(255, 255, 0);
        }

        public Color getColorPantalon2() {
            return new Color(255, 255, 0);
        }

        public Color getColorFranja2() {
            return new Color(255, 255, 0);
        }

        public Color getColorCalcetas2() {
            return new Color(255, 255, 0);
        }

        public Color getColorPortero2() {
            return new Color(0, 0, 0        );
        }

        public EstiloUniforme getEstilo2() {
            return EstiloUniforme.SIN_ESTILO;
        }

        class JugadorImpl implements JugadorDetalle {

            String nombre;
            int numero;
            Color piel, pelo;
            double velocidad, remate, presicion;
            boolean portero;
            Posicion posicion;

            public JugadorImpl(String nombre, int numero, Color piel, Color pelo,
                    double velocidad, double remate, double presicion, boolean portero) {
                this.nombre=nombre;
                this.numero=numero;
                this.piel=piel;
                this.pelo=pelo;
                this.velocidad=velocidad;
                this.remate=remate;
                this.presicion=presicion;
                this.portero=portero;
            }

            public String getNombre() {
                return nombre;
            }

            public Color getColorPiel() {
                return piel;
            }

            public Color getColorPelo() {
                return pelo;
            }

            public int getNumero() {
                return numero;
            }

            public boolean esPortero() {
                return portero;
            }

            public double getVelocidad() {
                return velocidad;
            }

            public double getRemate() {
                return remate;
            }

            public double getPresicion() {
                return presicion;
            }

        }

        public JugadorDetalle[] getJugadores() {
            return new JugadorDetalle[]{
                new JugadorImpl("Jugador", 1, new Color(255,204,102), new Color(255,102,51),1.0d,0.39d,0.68d, false),
                new JugadorImpl("Jugador", 2, new Color(255,204,102), new Color(0,0,255),1.0d,1.0d,1.0d, true),
                new JugadorImpl("Jugador", 3, new Color(255,204,102), new Color(255,102,51),1.0d,0.6d,0.73d, false),
                new JugadorImpl("Jugador", 4, new Color(255,204,102), new Color(255,102,51),1.0d,0.58d,0.72d, false),
                new JugadorImpl("Jugador", 5, new Color(255,204,102), new Color(255,255,0),1.0d,0.48d,0.82d, false),
                new JugadorImpl("Jugador", 6, new Color(255,204,102), new Color(255,255,0),1.0d,0.45d,0.81d, false),
                new JugadorImpl("Jugador", 7, new Color(255,204,102), new Color(204,153,0),1.0d,0.47d,0.83d, false),
                new JugadorImpl("Jugador", 8, new Color(255,204,102), new Color(204,153,0),1.0d,0.44d,0.83d, false),
                new JugadorImpl("Jugador", 9, new Color(255,204,102), new Color(0,0,0),1.0d,1.0d,1.0d, false),
                new JugadorImpl("Jugador", 10, new Color(255,204,102), new Color(0,0,0),1.0d,0.67d,1.0d, false),
                new JugadorImpl("Jugador", 11, new Color(255,204,102), new Color(0,0,0),1.0d,1.0d,1.0d, false)
            };
        }
    }

    public TacticaDetalle getDetalle() {
        return detalle;
    }
    
    public Posicion[] getPosicionSaca(SituacionPartido sp) {
    	return alineacion5;
    }

    public Posicion[] getPosicionRecive(SituacionPartido sp) {
    	return alineacion6;
    }

    Random rand = new Random();
    int paseGol = -1;
    int corriendo = -1;
    boolean leDio = false;
    boolean gambeta = false;
    LinkedList<Comando> c = new LinkedList<Comando>();
    
    public List<Comando> ejecutar(SituacionPartido sp){
        c.clear();
        
        Posicion[] miEquipo = sp.misJugadores();
        Posicion[] rivales = sp.rivales();
        Posicion pelota = sp.balon();
        alinearJugadores(sp.golesPropios(), sp.golesRival(), miEquipo, rivales, pelota);    
        moverArquero(c, pelota);
        int jmcb = pelota.indiceMasCercano(miEquipo);
        boolean arribaDePelota = miEquipo[jmcb].getY() > pelota.getY();
        int jmcb2 = pelota.indiceMasCercano(miEquipo, jmcb);
        int jmcb3 = pelota.indiceMasCercano(miEquipo, jmcb, jmcb2);
	    for (int j : pelota.indicesMasCercanos(miEquipo, jmcb)) {
            if (arribaDePelota && miEquipo[j].getY() < pelota.getY()) {
            	jmcb3 = j;
                break;
            } else if (!arribaDePelota && miEquipo[j].getY() > pelota.getY()) {
            	jmcb3 = j;
                break;
            }
        }
        c.add(new ComandoIrA(jmcb, pelota));
        if (jmcb2 != JA && jmcb3 != JA) {
        	 c.add(new ComandoIrA(jmcb2, pelota));
        	 c.add(new ComandoIrA(jmcb3, pelota));
        }
        int rematan[] = sp.puedenRematar();
        for (int i : rematan) {
    	    for (int j : miEquipo[i].indicesMasCercanos(miEquipo, i)) {
                if (miEquipo[j].getY() > 15 + miEquipo[i].getY() &&
                		miEquipo[j].getY() < 25 + miEquipo[i].getY() &&
                		numMarca(rivales, miEquipo[i], miEquipo[j]) == -1) {
                	pase(c, miEquipo, i, j);
                	leDio = true;
                	gambeta = false;
                    break;
                }
            }
    	    ataque(c, miEquipo, rivales, i, pelota);
            if (!leDio) {
            	if (zonaMuerta(miEquipo[i])) {
            		switch (i) {
						case 8:
							pase(c, miEquipo, i, J11);
							break;
						case 10:
							pase(c, miEquipo, i, J9);
							break;
						default:
							pase(c, miEquipo, i, miEquipo[i].indiceMasCercano(miEquipo, i));
					}
            	} else {
            		Posicion r = rivales[miEquipo[i].indiceMasCercano(rivales)];
            		double dis = miEquipo[i].distancia(r); 
            		if (dis < 15 && r.distancia(ARCO) < miEquipo[i].distancia(ARCO)) {
            			c.add(new ComandoGolpearBalon(i, ARCO, 1, 26));
            		} else {
            			correr(c, miEquipo, rivales, i, ARCO);
            		}
            	}
            }
        	if (i==JA || i==J1 || i==J3 || i==J4) {
        		c.add(new ComandoGolpearBalon(i, miEquipo[J10], 1, 24));
        	}
                 
        }
        leDio = false;
        return c;
    }
    
    /**
     * @param c
     * @param miEquipo
     * @param rivales
     * @param j
     * @param pelota
     */
    private void ataque(LinkedList<Comando> c, Posicion[] miEquipo, Posicion[] rivales, int j, Posicion pelota) {
        if ((j == J9 || j == J11) && miEquipo[j].distancia(ARCO) < 27 && !zonaMuerta(miEquipo[j]) && numMarca(rivales, miEquipo[j], ARCO) == -1) {
        	leDio = true;
        	double x = j == J9 ? ARCO.getX()+3.2 : ARCO.getX()-3.2;
        	 Posicion pos1 = new Posicion(x, ARCO.getY());
        	 Posicion pos2 = new Posicion(ARCO.getX(), ARCO.getY() + 3);
        	 Posicion pos = rand.nextDouble() <= 0.5 ? pos1 : pos2;
        	c.add(new ComandoGolpearBalon(j, pos, 1, 22));
        } else if ((j != J9 || j != J11) && miEquipo[j].distancia(ARCO) < 34 && !zonaMuerta(miEquipo[j]) &&	numMarca(rivales, miEquipo[j], ARCO) == -1) {
        	leDio = true;
        	double x = rand.nextDouble() <= 0.5 ? ARCO.getX()+2 : ARCO.getX()-2;
        	c.add(new ComandoGolpearBalon(j, new Posicion(x, ARCO.getY()), 1, 23));
        }
    }
    
    /**
     * @param golesProp
     * @param golesRiv
     * @param miEquipo
     * @param rivales
     */
    private void alinearJugadores(int golesProp, int golesRiv, Posicion[] miEquipo, Posicion[] rivales, Posicion pelota) {
    	boolean mJ3 = false;
    	boolean mJ4 = false;
		for (int r : miEquipo[J3].indicesMasCercanos(rivales)) {
			if (rivales[r].getY() < -20 && rivales[r].getX() < 0) {
				c.add(new ComandoIrA(J3, rivales[r]));
				mJ3 = true;
				break;
			}
		}
		if (!mJ3) {
			c.add(new ComandoIrA(J3, alineacion1[J3]));
		}
		for (int r : miEquipo[J4].indicesMasCercanos(rivales)) {
			if (rivales[r].getY() < -20 && rivales[r].getX() > 0) {
				c.add(new ComandoIrA(J4, rivales[r]));
				mJ4 = true;
				break;
			}
		}
		if (!mJ4) {
			c.add(new ComandoIrA(J4, alineacion1[J4]));
		}
		for (int i = 0; i < 11; i++) {
			if (i != 0 && i != J1 && i != J3 && i != J4) {
				c.add(new ComandoIrA(i, alineacion1[i]));
			}
		}
    	double xPel = pelota.getX();
    	double yPel = pelota.getY();
    	double dFonPel = yPel + 52.5;
    	double dArcPel = ARCO_MIO.distancia(pelota);
    	double ang = Math.asin(dFonPel / dArcPel);
    	double xCos = Math.cos(ang);
    	double ySin = Math.sin(ang);
    	
    	double xPos = xCos * 5;
    	double yPos = (ySin * 5) - 52.5;
    	if (xPel > 0) {
    		c.add(new ComandoIrA(J1, new Posicion(xPos, yPos)));
    	} else {
    		c.add(new ComandoIrA(J1, new Posicion(-xPos, yPos)));
    	}
    	
    	double xxPos = xCos * 35;
    	double yyPos = (ySin * 35) - 52.5;
    	if (xPel > 0) {
    		c.add(new ComandoIrA(J5, new Posicion(xxPos, yyPos)));
    	} else {
    		c.add(new ComandoIrA(J6, new Posicion(-xxPos, yyPos)));
    	}
    }
    
    /**
     * @param c
     * @param miEquipo
     * @param rivales
     * @param j
     * @param p
     */
    private void correr(LinkedList<Comando> c, Posicion[] miEquipo, Posicion[] rivales, int j, Posicion p) {
		boolean gambeteo = false;
		for (int i=0; i<6; i++) {
			int marca = numMarca(rivales, miEquipo[j], p);
			if (marca == -1) {
				gambeteo = true;
				break;
			} else {
				Posicion pRival = rivales[marca];
				p = nuevaDireccion(miEquipo[j], pRival);
	    	}
		}
		c.add(new ComandoIrA(j, p));
		if (gambeteo) {
			c.add(new ComandoGolpearBalon(j));
		} else {
			c.add(new ComandoGolpearBalon(j, miEquipo[j].indiceMasCercano(miEquipo), 0.7, 55));
		}
		corriendo = j;
		gambeta = false;
    }
    
    /**
     * @param j
     * @param pRival
     * @return
     */
    private Posicion nuevaDireccion(Posicion j, Posicion pRival) {
    	Posicion dir;
		double b1 = pRival.getX() - j.getX();
		double b2 = pRival.getY() - j.getY();
		boolean aLaDerecha = pRival.getX() > j.getX();
		double d1 = aLaDerecha ? -b2 : b2;
		double d2 = aLaDerecha ? b1 : -b1;
		dir = new Posicion(d1 + j.getX(), d2 + j.getY());
    	return dir;
    }
    
    /**
     * @param rivales
     * @param j
     * @param d
     * @return
     */
    private int numMarca(Posicion[] rivales, Posicion j, Posicion d) {
    	int marca = -1;
    	if (j.distancia(rivales[j.indiceMasCercano(rivales)]) < 13) {
    		double a1 = d.getX() - j.getX();
    		double a2 = d.getY() - j.getY();
    		double disd = j.distancia(d);
        	for (int rr : j.indicesMasCercanos(rivales)) {
        		double disr = j.distancia(rivales[rr]);
        		double disrd = d.distancia(rivales[rr]);
        		if (disr < 12 && disd > disrd) {
            		double b1 = rivales[rr].getX() - j.getX();
            		double b2 = rivales[rr].getY() - j.getY(); 
            		double cos = (Math.abs((a1*b1)+(a2*b2))) / 
            				((Math.sqrt(Math.pow(a1, 2)+Math.pow(a2, 2))) * 
            						(Math.sqrt(Math.pow(b1, 2)+Math.pow(b2, 2))));
        			double ang = Math.toDegrees(Math.acos(cos));
        			if (ang < 13) {
        				marca = rr;
        				break;
        			}
        		}
            }
    	}
    	return marca;
    }
    
    /**
     * @param c
     * @param miEquipo
     * @param jOrigen
     * @param jDestino
     */
    private void pase(LinkedList<Comando> c, Posicion[] miEquipo, int jOrigen, int jDestino) {
		double xx = miEquipo[jDestino].getX();
		double yy = miEquipo[jDestino].getY();
		Posicion pDestino = new Posicion(xx, yy);
		double d = miEquipo[jOrigen].distancia(pDestino);
		double f = 0;
		if (d > 35) {
			f = 1;
		} else if (30 <= d && d < 35) {
			f = 0.95;
		} else if (28 <= d && d < 30) {
			f = 0.9;
		} else {
			f = 0.85;
		}
		c.add(new ComandoGolpearBalon(jOrigen, pDestino, f, 25));
	}
    
    /**
     * @param j
     * @return
     */
    private boolean zonaMuerta(Posicion j) {
    	return j.getX() > LAT - 5 || j.getX() < -LAT + 5 || j.getY() > FON - 8;
    }
    
    /**
     * @param c
     * @param pelota
     */
    private void moverArquero(LinkedList<Comando> c, Posicion pelota) {
    	double xx = pelota.getX();
    	double poste = Constantes.posteDerArcoInf.getX();
    	if (xx > poste) {
    		c.add(new ComandoIrA(JA, new Posicion(1, -52)));
    	} else if (xx < -poste) {
    		c.add(new ComandoIrA(JA, new Posicion(-1, -52)));
    	} else {
    		c.add(new ComandoIrA(JA, new Posicion(0, -52)));
    	}
    }
}